#include <iostream>
#include <memory>

/*
不带引用计数的智能指针
auto_ptr (introduced in c++98, deprecated in c++11)
拷贝构造和拷贝赋值实际上在转移所有权,
而且是不明显的转移，容易忽视导致bug，不推荐使用

scoped_ptr(不在标准库中，在第三方库中，如boost)
没有拷贝和移动语义，提供绝对的所有权

unique_ptr(introduced in c++11,推荐使用)
提供绝对的所有权
支持移动语义,需要明确使用move函数
*/

#if 0
int main() {
    std::auto_ptr<int> pa = std::auto_ptr<int>(new int(42));
    std::auto_ptr<int> pa2 = pa;

    std::unique_ptr<int> pu = std::unique_ptr<int>(new int(24));
    /* std::unique_ptr<int> pu2 = pu; // │Call to deleted constructor of
     * 'std::unique_ptr<int>' */
    std::unique_ptr<int> pu3 = std::move(pu);  // support move operation
    std::cout << *pu3 << std::endl;            // pu不再可用
}
#endif

/*

带引用计数的智能指针
shared_ptr和weak_ptr

多个智能指针可以管理同一个资源

*/

template <typename T>
class RefCnt {
public:
    RefCnt(T* ptr = nullptr) : _ptr(ptr) {
        if (ptr) _count = 1;
    }

    void incRef() {
        _count++;
    }

    int decRef() {
        return --_count;
    }

private:
    T* _ptr;
    int _count;
};

template <typename T>
class SmartPtr {
public:
    SmartPtr(T* ptr = nullptr) : _ptr(ptr) {
        _pRefCnt = new RefCnt<T>(_ptr);
    }

    ~SmartPtr() {
        if (0 == _pRefCnt->decRef()) {
            delete _ptr;
            _ptr = nullptr;
            delete _pRefCnt;
            _pRefCnt = nullptr;
        }
    }

    SmartPtr(const SmartPtr<T>& other)
        : _ptr(other._ptr), _pRefCnt(other._pRefCnt) {
        if (_ptr) {
            _pRefCnt->incRef();
        }
    }

    SmartPtr<T>& operator=(const SmartPtr<T>& other) {
        if (this == &other) return *this;

        if (0 == _pRefCnt->decRef()) {
            delete _ptr;
        }

        _ptr = other._ptr;
        _pRefCnt = other._pRefCnt;
        _pRefCnt->incRef();
        return *this;
    }

    T& operator*() {
        return *_ptr;
    }

    T* operator->() {
        return _ptr;
    }

private:
    T* _ptr;
    RefCnt<T>* _pRefCnt;
};
int main() {
    SmartPtr<int> p1 = SmartPtr<int>(new int(42));
    SmartPtr<int> p2 = p1;
    SmartPtr<int> p3;
    p3 = p2;
    std::cout << *p1 << " " << *p2 << " " << *p3 << std::endl;
    *p1 = 21;
    std::cout << *p1 << " " << *p2 << " " << *p3 << std::endl;
}
